var runtimeChampsBattle = null;
var Code = null;
var QUARTER_REQUEST_LIMIT = 35;

exports._initRuntime = function() {
    runtimeChampsBattle = gConfRuntime.champsbattle;
    Code = runtimeChampsBattle.Code;
}

exports.get = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (user.status.level < gConfGlobal.ChampsBattleOpenLevel) {
            resp.data.code = Code.kNotEnterable; break;
        }

        var schedule = runtimeChampsBattle.getSchedule();
        if (runtimeChampsBattle.StepWaiting == schedule.step) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        var champsBattle = player.getChampsBattle();
        player.requestChampsBattle(req, resp, function() {
            if (resp.data.registered) {
                if (!resp.data.enterable) {
                    champsBattle.enterable = false;
                    player.markDirty('champsbattle.enterable');
                }
            } else if (schedule.step > runtimeChampsBattle.StepRegister) {
                champsBattle.enterable = false;
                player.markDirty('champsbattle.enterable');
            }
            
            resp.data.champsbattle = champsBattle;
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.register = function(player, req, resp, onHandled) {
    do {
        var schedule = runtimeChampsBattle.getSchedule();
        if (schedule.step != runtimeChampsBattle.StepRegister || !schedule.keep) {
            resp.code = 1; resp.desc = 'not register time'; break;
        }

        var champsBattle = player.getChampsBattle();
        if (!champsBattle.enterable) {
            resp.data.code = Code.kNotEnterable; break;
        }

        var ranks = gRank.getRewardRanks();
        var fightForce = 0;
        var topRanks = {};
        objectForEach(ranks, function(uid, rank) {
            var userRank = +rank;
            if (userRank <= gConfGlobal.ChampsBattleRankMin) {
                topRanks[uid] = userRank;
                var userInfo = gUserInfo.getUser(uid);
                if (userInfo) {
                    fightForce += (userInfo.fight_force || 0);
                }
            }
        });
        
        req.args.serverStartTime = gConfGlobalServer.ServerStartTime;
        req.args.ranks = topRanks;
        req.args.fightForce = fightForce;
        player.requestChampsBattle(req, resp, function() {
            delete req.args.serverStartTime;
            delete req.args.ranks;
            delete req.args.fightForce;
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.saveTeams = function(player, req, resp, onHandled) {
    var user = player.user;

    do {
        var teams = req.args.teams;
        if (!teams) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

        if (user.status.level < gConfGlobal.ChampsBattleOpenLevel) {
            resp.data.code = Code.kNotEnterable; break;
        }

        var schedule = runtimeChampsBattle.getSchedule();
        if (runtimeChampsBattle.StepWaiting == schedule.step) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        var champsBattle = player.getChampsBattle();
        if (!champsBattle.enterable) {
            resp.data.code = Code.kNotEnterable; break;
        }

        var roles = user.role;
        var usedRoles = {};
        var teamOK = true;
        var teamNum = 0;

        for (var id in teams) {
            id = +id;
            if (id < 1 || id > gConfGlobal.ChampsBattleTeamCount) {
                teamOK = false; break;
            }

            var team = teams[id];
            var teamRoleNum = 0;
            for (var pos in team) {
                pos = +pos;
                if (pos < 0 || pos >= 9) {
                    teamOK = false; break;
                }

                var rid = team[pos];
                if (!rid) {
                    delete team[pos];
                    continue;
                }

                if (!roles[rid]) {
                    teamOK = false; break;
                }

                if (usedRoles[rid]) {
                    teamOK = false; break;
                }

                usedRoles[rid] = true;
                teamRoleNum++;
            }

            if (!teamOK) {
                break;
            }

            if (teamRoleNum < 1) {
                delete teams[id];
            }

            if (teamRoleNum > gConfGlobal.ChampsBattleTeamRoleCount) {
                teamOK = false; break;
            }

            teamNum++;
        }

        if (teamNum < 1 || teamNum > gConfGlobal.ChampsBattleTeamCount) {
            teamOK = false;
        }

        if (!teamOK) {
            resp.code = 1; resp.desc = 'invalid team'; break;
        }


        player.calculateAllRoleAttr();
        req.args.userData = {
            role: user.role,
            pet: user.pet,
            roleAttrs: player.roleAttrs,
        }
        
        player.requestChampsBattle(req, resp, function() {
            delete req.args.userData;
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.adjustTeam = function(player, req, resp, onHandled) {
    var user = player.user;

    do {
        if (!req.args.teams) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

        var schedule = runtimeChampsBattle.getSchedule();
        if (runtimeChampsBattle.StepWaiting == schedule.step) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        var champsBattle = player.getChampsBattle();
        if (!champsBattle.enterable) {
            resp.data.code = Code.kNotEnterable; break;
        }
        
        var teams = req.args.teams;
        var usedRoles = {};
        var teamOK = true;
        var teamNum = 0;

        for (var id in teams) {
            id = +id;
            if (id < 1 || id > gConfGlobal.ChampsBattleTeamCount) {
                teamOK = false; break;
            }

            var team = teams[id];
            var teamRoleNum = 0;
            for (var pos in team) {
                pos = +pos;
                if (pos < 0 || pos >= 9) {
                    teamOK = false; break;
                }

                var rid = team[pos];
                if (!rid) {
                    delete team[pos];
                    continue;
                }

                if (usedRoles[rid]) {
                    teamOK = false; break;
                }

                usedRoles[rid] = true;
                teamRoleNum++;
            }

            if (!teamOK) {
                break;
            }

            if (teamRoleNum < 1) {
                delete teams[id];
            }

            if (teamRoleNum > gConfGlobal.ChampsBattleTeamRoleCount) {
                teamOK = false; break;
            }

            teamNum++;
        }

        if (teamNum < 1 || teamNum > gConfGlobal.ChampsBattleTeamCount) {
            teamOK = false;
        }

        if (!teamOK) {
            resp.code = 1; resp.desc = 'invalid team'; break;
        }

        player.requestChampsBattle(req, resp, function() {
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.getField = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (user.status.level < gConfGlobal.ChampsBattleOpenLevel) {
            resp.data.code = Code.kNotEnterable; break;
        }

        var schedule = runtimeChampsBattle.getSchedule();
	    if (!runtimeChampsBattle.isFightingSchedule(schedule)) {
            resp.data.code = Code.kScheduleTimeout; break;
        }

        var champsBattle = player.getChampsBattle();
        if (!champsBattle.enterable) {
            resp.data.code = Code.kNotEnterable; break;
        }

        var nowQuarter = Math.floor(Date.getStamp()/300);
        if (nowQuarter != player.lastMsgQuarter) {
            champsBattle.quarterRequestCount = 0;
        }

        if (champsBattle.quarterRequestCount > QUARTER_REQUEST_LIMIT) {
            resp.data.code = Code.kFrequently; break;            
        }
        
        champsBattle.quarterRequestCount++;
        player.markDirty('champsbattle.quarterRequestCount');

        player.requestChampsBattle(req, resp, function() {
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.getFieldCity = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (isNaN(req.args.cityId)) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

        if (user.status.level < gConfGlobal.ChampsBattleOpenLevel) {
            resp.data.code = Code.kNotEnterable; break;
        }

	    var schedule = runtimeChampsBattle.getSchedule();
	    if (!runtimeChampsBattle.isFightingSchedule(schedule)) {
            resp.data.code = Code.kScheduleTimeout; break;
        }

        var champsBattle = player.getChampsBattle();
        if (!champsBattle.enterable) {
            resp.data.code = Code.kNotEnterable; break;
        }

        var nowQuarter = Math.floor(Date.getStamp()/300);
        if (nowQuarter != player.lastMsgQuarter) {
            champsBattle.quarterRequestCount = 0;
        }

        if (champsBattle.quarterRequestCount > QUARTER_REQUEST_LIMIT) {
            resp.data.code = Code.kFrequently; break;            
        }
        
        champsBattle.quarterRequestCount++;
        player.markDirty('champsbattle.quarterRequestCount');
        
        player.requestChampsBattle(req, resp, function() {
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.getRecords = function(player, req, resp, onHandled) {
    do {
	    var schedule = runtimeChampsBattle.getSchedule();
	    if (!runtimeChampsBattle.isFightingSchedule(schedule)) {
            resp.data.code = Code.kScheduleTimeout; break;
        }

        var champsBattle = player.getChampsBattle();
        if (!champsBattle.enterable) {
            resp.data.code = Code.kNotEnterable; break;
        }

        var nowQuarter = Math.floor(Date.getStamp()/300);
        if (nowQuarter != player.lastMsgQuarter) {
            champsBattle.quarterRequestCount = 0;
        }

        if (champsBattle.quarterRequestCount > QUARTER_REQUEST_LIMIT) {
            resp.data.code = Code.kFrequently; break;            
        }
        
        champsBattle.quarterRequestCount++;
        player.markDirty('champsbattle.quarterRequestCount');
        
        player.requestChampsBattle(req, resp, function() {
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.moveTeam = function(player, req, resp, onHandled) {
    do {
        if (isNaN(req.args.id) || isNaN(req.args.cityId)) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

	    var schedule = runtimeChampsBattle.getSchedule();
	    if (!runtimeChampsBattle.isFightingSchedule(schedule)) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        player.requestChampsBattle(req, resp, function() {
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.reliveTeam = function(player, req, resp, onHandled) {
    do {
        if (isNaN(req.args.id) || isNaN(req.args.cash)) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

	    var schedule = runtimeChampsBattle.getSchedule();
	    if (!runtimeChampsBattle.isFightingSchedule(schedule)) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        req.args.ownCash = player.user.status.cash;
        player.requestChampsBattle(req, resp, function() {
            if (!resp.code && !resp.data.code) {
                var cash = +resp.data.cash;
                if (cash < 0) {
                    player.costResource('cash', -cash);
                }
            }
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.summon = function(player, req, resp, onHandled) {
    do {
        if (isNaN(req.args.id)) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

	    var schedule = runtimeChampsBattle.getSchedule();
	    if (!runtimeChampsBattle.isFightingSchedule(schedule)) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        player.requestChampsBattle(req, resp, function() {
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.contribute = function(player, req, resp, onHandled) {
    do {
        if (isNaN(req.args.id) || isNaN(req.args.resource)) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

	    var schedule = runtimeChampsBattle.getSchedule();
	    if (!runtimeChampsBattle.isFightingSchedule(schedule)) {
            resp.data.code = Code.kScheduleTimeout; break;
        }
        
        player.requestChampsBattle(req, resp, function() {
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.getStepAward = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (user.status.level < gConfGlobal.ChampsBattleOpenLevel) {
            resp.data.code = Code.kNotEnterable; break;
        }
        
	    var schedule = runtimeChampsBattle.getSchedule();
        if (schedule.keep || (schedule.step <= runtimeChampsBattle.StepRegister)) {
            resp.code = 1; resp.desc = 'not award time'; break;
        }

        var step = schedule.step;
        var champsBattle = player.getChampsBattle();
        if (champsBattle.awardStep >= schedule.step) {
            resp.code = 1; resp.desc = 'got'; break;
        }
        
        var support = champsBattle.support[step];
        if (!champsBattle.enterable && !support) {
            resp.code = 1; resp.desc = 'nothing'; break;
        }

        req.args.step = step;
        req.args.support = support;
        player.requestChampsBattle(req, resp, function() {
            if (!resp.code && !resp.data.code) {
                var user = player.user;
                if (resp.data.topAward) {
                    var topAwardConf = gConfChampsBattleReward['Top'][step][-1];
                    resp.data.awards = player.addAwards(topAwardConf.Awards);
                    delete resp.data.topAward;
                }

                if (resp.data.supportAward) {
                    var stepConf = gConfChampsBattleSchedule[step];
                    var levelConf = gConfLevel[user.status.level];
                    var gold = Math.floor(levelConf.ChampsBattleSupport * stepConf.SupportGold * 10000);
                    resp.data.supportAwards = player.addAwards([['user', 'gold', gold]]);
                    delete resp.data.supportAward;
                }
                
                var leagueWar = user.league_war;
                if (leagueWar && resp.data.glory) {
                    var maxGlory = gConfGradeLevel[leagueWar.grade_level].GloryLimit;
                    var gloryGot = Math.min(maxGlory - leagueWar.glory, +resp.data.glory || 0);
                    leagueWar.glory += gloryGot;
                    player.markDirty('league_war.glory');
                    resp.data.glory = gloryGot;
                } else {
                    delete resp.data.glory;
                }

                champsBattle.awardStep = step;
                player.markDirty('champsbattle.awardStep');
                
                resp.data.awardStep = step;
            }
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.getFinalAward = function(player, req, resp, onHandled) {
    do {
	    var schedule = runtimeChampsBattle.getSchedule();

        var stepConf = gConfChampsBattleSchedule[schedule.step];
        if (schedule.keep || schedule.step != runtimeChampsBattle.StepFinal) {
            resp.code = 1; resp.desc = 'not award time'; break;
        }

        var champsBattle = player.getChampsBattle();
        if (champsBattle.finalAward) {
            resp.code = 1; resp.desc = 'got'; break;
        }
        
        player.requestChampsBattle(req, resp, function() {
            if (!resp.code && !resp.data.code) {
                var fieldId = +resp.data.fieldId;
                var win = +resp.data.win;
                var step = gConfChampsBattleField[fieldId].Step;
                if (step < runtimeChampsBattle.StepFinal) {
                    win = 0;
                }

                champsBattle.finalAward = 1;
                player.markDirty('champsbattle.finalAward');

                var awardConf = gConfChampsBattleReward['Final'][step][win];
                resp.data.awards = player.addAwards(awardConf.Awards);
            }
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.support = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (isNaN(req.args.sid)) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

        if (user.status.level < gConfGlobal.ChampsBattleOpenLevel) {
            resp.data.code = Code.kNotEnterable; break;
        }
        
        var sid = +req.args.sid;
	    var schedule = runtimeChampsBattle.getSchedule();
        var step = schedule.step + 1;
        var stepConf = gConfChampsBattleSchedule[step];
        if (!stepConf || !stepConf.Group || schedule.keep) {
            resp.schedule = schedule;
            resp.code = 1; resp.desc = 'not support time'; break;
        }

        var champsBattle = player.getChampsBattle();
        if (champsBattle.support.hasOwnProperty(step)) {
            resp.code = 1; resp.desc = 'supported'; break;
        }
        
        req.args.step = step;
        player.requestChampsBattle(req, resp, function() {
            if (!resp.code && !resp.data.code) {
                champsBattle.support[step] = sid;
                player.markDirty('champsbattle.support');
            }
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}

exports.getReplay = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (isNaN(req.args.id)) {
            resp.code = 1; resp.desc = 'invalid args'; break;
        }

        if (user.status.level < gConfGlobal.ChampsBattleOpenLevel) {
            resp.data.code = Code.kNotEnterable; break;
        }
        
        player.requestChampsBattle(req, resp, function() {
            onHandled();
        });
        return;
    } while (false);

    onHandled();
}
